/* File: ast_decl.cc
 * -----------------
 * Implementation of Decl node classes.
 */
#include "ast_decl.h"
#include "ast_type.h"
#include "ast_stmt.h"
#include "errors.h"

bool Scope::InsertDecl(Decl *decl) {
        Decl *find = map->Lookup(decl->Name());
        if ( find != NULL ) {
                ReportError::DeclConflict(decl,find);
                return true;
        }
        map->Enter(decl->Name(),decl);
        return false;
}
         
Decl::Decl(Identifier *n) : Node(*n->GetLocation()), scope(new Scope) {
    Assert(n != NULL);
    (id=n)->SetParent(this); 
}

VarDecl::VarDecl(Identifier *n, Type *t) : Decl(n) {
    Assert(n != NULL && t != NULL);
    (type=t)->SetParent(this);
}

void VarDecl::Verify() {
        if (type->checkPrim()) {
                return;
        }
        Scope *t = scope;
} 

ClassDecl::ClassDecl(Identifier *n, NamedType *ex, List<NamedType*> *imp, List<Decl*> *m) : Decl(n) {
    // extends can be NULL, impl & mem may be empty lists but cannot be NULL
    Assert(n != NULL && imp != NULL && m != NULL);     
    extends = ex;
    if (extends) extends->SetParent(this);
    (implements=imp)->SetParentAll(this);
    (members=m)->SetParentAll(this);
}

void ClassDecl::UseScope(Scope *scope) {
        this->scope->parent = scope;
        this->scope->classDecl = this;
        for(int i = 0; i < members->NumElements(); i++) {
                this->scope->InsertDecl(members->Nth(i));
        }
        for(int i = 0; i < members->NumElements(); i++) {
                members->Nth(i)->UseScope(this->scope);
        }
}

void ClassDecl::Verify() {
        
}

InterfaceDecl::InterfaceDecl(Identifier *n, List<Decl*> *m) : Decl(n) {
    Assert(n != NULL && m != NULL);
    (members=m)->SetParentAll(this);
}

void InterfaceDecl::UseScope(Scope *scope) {
        this->scope->parent = scope;
        for(int i = 0; i < members->NumElements(); i++) {
                this->scope->InsertDecl(members->Nth(i));
        }
        for(int i = 0; i < members->NumElements(); i++) {
                members->Nth(i)->UseScope(this->scope);
        }
        
}
	
void InterfaceDecl::Verify() {
        
}

FnDecl::FnDecl(Identifier *n, Type *r, List<VarDecl*> *d) : Decl(n) {
    Assert(n != NULL && r!= NULL && d != NULL);
    (returnType=r)->SetParent(this);
    (formals=d)->SetParentAll(this);
    body = NULL;
}

void FnDecl::SetFunctionBody(Stmt *b) { 
    (body=b)->SetParent(this);
}

void FnDecl::UseScope(Scope *scope) {
        this->scope->parent = scope;
        this->scope->fn = this;
        for(int i = 0; i < formals->NumElements(); i++) {
                this->scope->InsertDecl(formals->Nth(i));
        }
        for(int i = 0; i < formals->NumElements(); i++) {
                formals->Nth(i)->UseScope(this->scope);
        }
        if (body) {
                body->UseScope(this->scope);
        }
}

void FnDecl::Verify() {
        
}